<template>
  <MyDvBox
    class="my-dv-list"
    :class="classes"
    :default-height="contentHeight"
    v-bind="$attrs"
  >
    <table
      v-if="header"
      ref="header"
      class="my-dv-list__header"
      cellspacing="0"
      cellpadding="0"
    >
      <ListColGroup
        :columns="tableColumns"
        :default-width="cellWidth"
      ></ListColGroup>
      <thead>
        <tr style="display: flex">
          <th
            v-for="(col, index) in tableColumns"
            :key="`tr_${_uid}_col_${index}`"
            :style="{
              width: `${columns[index].width}px`,
              maxWidth: `${columns[index].width}px`,
              display: 'flex',
              justifyContent: 'center',
            }"
          >
            <slot name="column" :col="col" :index="index">
              {{ col.label }}
            </slot>
          </th>
        </tr>
      </thead>
    </table>
    <MyMarquee
      ref="marquee"
      class="my-dv-list__body-wrapper"
      :data="rows"
      :style="bodyStyle"
      v-bind="scrollProps"
      @resize="marqueeResize"
    >
      <table
        v-if="rows.length"
        class="my-dv-list__body"
        cellspacing="0"
        cellpadding="0"
      >
        <ListColGroup
          :columns="tableColumns"
          :default-width="cellWidth"
        ></ListColGroup>
        <slot name="table" :rows="rows">
          <tr
            v-for="(row, rowIndex) in rows"
            :key="`row_${rowIndex}`"
            style="display: flex"
            @click="handleRowClick(row)"
          >
            <td
              v-for="(item, itemIndex) in getRow(row)"
              :key="`item_${itemIndex}`"
              :style="{
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                flex: 1,
                width: `${columns[itemIndex].width}px`,
                maxWidth: `${columns[itemIndex].width}px`,
                whiteSpace: 'nowrap',
                overflow: 'hidden',
                textOverflow: 'ellipsis',
              }"
            >
              <slot
                :name="getSlotName(itemIndex)"
                :row="row"
                :item="item"
                :index="itemIndex"
                :rowIndex="rowIndex"
              >
                {{ item }}
              </slot>
            </td>
          </tr>
        </slot>
      </table>
      <div v-else class="my-dv-list__empty">
        <slot name="empty">暂无数据</slot>
      </div>
    </MyMarquee>
  </MyDvBox>
</template>
<script>
  /**
   * 列表
   * @module $ui/dv/my-dv-list
   */
  import { MyDvBox } from '$ui/dv'
  import ListColGroup from '$ui/dv/packages/my-dv-list/ColGroup'
  import { MyMarquee } from '$ui'
  export default {
    name: 'MyDvList',
    components: {
      MyDvBox,
      ListColGroup,
      MyMarquee,
    },
    /**
     * 属性参数
     * @member props
     * @property {String[]|Object[]} [columns] 数据列
     * @property {string} [columns.label] 列头文本
     * @property {string} [columns.prop] 列名称，如果行是对象格式，必须要设置
     * @property {number} [columns.width] 列宽度
     * @property {Array} [rows] 数据行
     * @property {boolean} [header=true] 显示列头
     * @property {boolean} [border] 显示边框
     * @property {boolean} [radius] 显示圆角
     * @property {Boolean|Object} [scroll] 滚动配置
     */
    props: {
      // [{label, prop, width}]
      columns: {
        type: Array,
        default() {
          return []
        },
      },
      rows: {
        type: Array,
        default() {
          return []
        },
      },
      header: {
        type: Boolean,
        default: true,
      },
      border: Boolean,
      radius: Boolean,
      background: Boolean,
      scroll: [Boolean, Object],
    },
    data() {
      return {
        headerHeight: 0,
        headerWidth: 0,
        contentHeight: 'auto',
      }
    },
    computed: {
      tableColumns() {
        return this.columns.map((col) => {
          return typeof col === 'object' ? col : { label: col }
        })
      },
      classes() {
        return {
          'is-border': this.border,
          'is-radius': this.radius,
          'is-no-header': !this.header,
          'is-odd': this.rows.length % 2 === 0,
          'is-no-background': !this.background,
        }
      },
      bodyStyle() {
        return {
          height: `calc(100% - ${this.headerHeight}px)`,
        }
      },
      scrollProps() {
        return {
          disabled: !this.scroll,
          speed: 0.5,
          ...this.scroll,
        }
      },
      cellWidth() {
        let total = this.headerWidth
        let count = 0
        this.tableColumns.forEach((n) => {
          if (n.width || n.minWidth) {
            total -= n.width || n.minWidth || 0
          } else {
            ++count
          }
        })
        return count > 0 ? total / count : 0
      },
    },
    watch: {
      header() {
        this.updateHeaderHeight()
      },
    },
    mounted() {
      this.updateHeaderHeight()
      this.marqueeResize({})
    },
    methods: {
      getRow(row) {
        if (Array.isArray(row)) {
          return row
        }
        return this.tableColumns.map((col) => row[col.prop])
      },
      getSlotName(itemIndex) {
        const col = this.tableColumns[itemIndex]
        return col?.prop
      },
      updateHeaderHeight() {
        const rect = this.$refs?.header?.getBoundingClientRect()
        this.headerHeight = rect ? rect.height : 0
        this.headerWidth = rect ? rect.width : 0
        if (this.$refs.marquee) {
          this.$nextTick(this.$refs.marquee.renderCopyHtml)
        }
      },
      marqueeResize({ height }) {
        if (this.$attrs.height) {
          this.contentHeight = this.$attrs.height
        } else {
          this.contentHeight = height ? `${height}px` : 'auto'
        }
      },
      handleRowClick(e) {
        this.$emit('rowClick', e)
      },
    },
  }
</script>
<style lang="scss">
  @import '$ui/dv/style/vars';
  @include b(dv-list) {
    table {
      width: 100%;
      border-collapse: collapse;
    }
    td,
    th {
      padding: 8px 10px;
      text-align: left;
    }
    @include e(header) {
      color: $--dv-text-normal;
      background: $--dv-color-table-header;
      th {
        border-bottom: transparent !important;
      }
    }
    @include e(body-wrapper) {
      color: $--dv-text-normal;
      background: $--dv-color-background;
    }
    @include e(body) {
      tr:nth-child(odd) {
        background: $--dv-color-table-stripe;
      }
      tr:hover {
        background: $--dv-color-table-hover;
      }
    }
    @include e(empty) {
      padding: 20px;
      color: $--dv-text-secondary;
      text-align: center;
    }
    @include when(border) {
      td,
      th {
        border: 1px solid $--dv-color-border;
      }
    }
    @include when(radius) {
      @include e(header) {
        border-radius: 4px 4px 0 0;
      }
      @include e(body-wrapper) {
        border-radius: 0 0 4px 4px;
      }
      @include when(no-header) {
        @include e(body-wrapper) {
          border-radius: 4px 4px 4px 4px;
        }
      }
    }
    @include when(odd) {
      .my-marquee__copy-content {
        tr:nth-child(odd) {
          background: transparent;
        }
        tr:nth-child(even) {
          background: $--dv-color-table-stripe;
        }
      }
    }
    @include when(no-background) {
      @include e(body-wrapper) {
        background: transparent;
      }
      @include e(header) {
        background: transparent;
      }
    }
  }
</style>
